/*
 * Copyright 2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.lightframework.jamwiki.servlets;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.jamwiki.DataAccessException;
import org.jamwiki.WikiBase;
import org.jamwiki.servlets.ServletUtil;
import org.jamwiki.servlets.ServletUtilEx;
import org.jamwiki.servlets.WikiPageInfo;
import org.lightframework.jamwiki.EnvironmentEx;
import org.lightframework.jamwiki.RuntimeWikiException;
import org.lightframework.jamwiki.model.Topic;
import org.lightframework.jamwiki.model.VirtualWiki;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
import org.springframework.web.servlet.ModelAndView;

/**
 * request context object
 *
 * @author fenghm(live.fenghm@gmail.com)
 */
public class WikiContext {

	private static final ThreadLocal<WikiContext> ctx = new ThreadLocal<WikiContext>();

	static void setIfNotSet(HttpServletRequest request,ModelAndView mv) throws Exception{
		setIfNotSet(request, mv, (WikiPageInfo)mv.getModel().get(ServletUtil.PARAMETER_PAGE_INFO));
	}	
	
	static void setIfNotSet(HttpServletRequest request,ModelAndView mv,WikiPageInfo pageInfo) throws Exception{
		if(request instanceof SecurityContextHolderAwareRequestWrapper){
			request = (HttpServletRequest)((SecurityContextHolderAwareRequestWrapper)request).getRequest();
		}
		
		WikiContext context = ctx.get();
		if(null == context){
			context = new WikiContext();
			context.initialize(request, mv, pageInfo);
			ctx.set(context);
		}else{
			if(!context.mv.equals(mv)){
				context.setModelAndView(mv);
			}
			if(!context.pageInfo.equals(pageInfo)){
				context.setPageInfo(pageInfo);
			}
		}
	}
	
	public static void reset(){
		ctx.set(null);
	}
	
	public static WikiContext get(){
		return ctx.get();
	}
	
	public static boolean isEmbedMode(){
		return get().embed;
	}
	
	public static String returnto(){
	    String returnto = request().getParameter(EnvironmentEx.CONST_RETURN_TO);
	    if(null == returnto && isEmbedMode()){
	    	returnto = (String)request().getSession().getAttribute(EnvironmentEx.CONST_RETURN_TO);
	    }
	    return returnto;
	}
	
	public static String contextPath(){
		return get().contextPath;
	}
	
	public static VirtualWiki wiki(){
		return get().getVirtualWiki();
	}
	
	public static String wikiName(){
		return wiki().getName();
	}
	
	public static Topic topic(){
		return get().getTopic();
	}
	
	public static boolean isViewTopic(){
		return get().isViewArticle();
	}
	
	public static boolean isEditTopic(){
		return request().getRequestURI().contains("/Special:Edit");
	}
	
	public static HttpServletRequest request(){
		return get().getRequest();
	}

	private HttpServletRequest request;
	private String             contextPath;
	private VirtualWiki        virtualWiki;
	private Topic              topic;
	private WikiPageInfo       pageInfo;
	private ModelAndView       mv;
	private boolean            embed;
	private boolean            isDashboardPage;

	public HttpServletRequest getRequest() {
    	return request;
    }
	
	public boolean isWikiRequest(){
		return null != pageInfo;
	}
	
	public boolean isViewArticle(){
		//TODO : REVIEW isViewArticle
		if(null != pageInfo && !pageInfo.getSpecial()){
			Topic topic = getTopic();
			if(null != topic && !request.getRequestURI().contains("/Special:")){
				return topic.isArticle();
			}
		}
		return false;
	}
	
	public boolean isDashboardPage(){
		return isDashboardPage;
	}

	public VirtualWiki getVirtualWiki(){
		if(null == virtualWiki || !virtualWiki.getName().equals(pageInfo.getVirtualWikiName())){
			try {
	            virtualWiki = new VirtualWiki(WikiBase.getDataHandler().lookupVirtualWiki(pageInfo.getVirtualWikiName()));
            } catch (DataAccessException e) {
            	throw new RuntimeWikiException(e);
            }
		}
    	return virtualWiki;
    }

	public Topic getTopic() {
		if(null == topic || !topic.getName().equals(pageInfo.getTopicName())){
			org.jamwiki.model.Topic jamtopic = 
				(org.jamwiki.model.Topic)mv.getModel().get(ServletUtil.PARAMETER_TOPIC_OBJECT);
			if(null == jamtopic && !StringUtils.isBlank(pageInfo.getTopicName())){
				try {
	                jamtopic = ServletUtilEx.initializeTopic(getVirtualWiki().getName(), pageInfo.getTopicName());
                } catch (org.jamwiki.WikiException e) {
                	throw new RuntimeWikiException(e.getMessage(),e);
                }
			}
			if(null != jamtopic){
    			topic = new Topic(jamtopic);
			}
		}
    	return topic;
    }

	public WikiPageInfo getPageInfo() {
    	return pageInfo;
    }
	
	void setPageInfo(WikiPageInfo pageInfo){
		this.pageInfo = pageInfo;
	}

	void setModelAndView(ModelAndView mv){
		this.mv = mv;
	}
	
	private void initialize(HttpServletRequest request,ModelAndView mv,WikiPageInfo pageInfo) throws Exception{
		this.pageInfo    = pageInfo;		
		this.mv          = mv;
		this.request     = request;
		this.contextPath = ServletUtilEx.getContextPath(request);
		
		if(null != mv){
			this.isDashboardPage = Boolean.valueOf(true).equals(mv.getModel().get(DashboardServlet.IS_DASHBOARD_PAGE_KEY));
		}
		
		//embed mode ?
		if("true".equals(request.getParameter("embed"))){
			request.getSession().setAttribute("wiki_embed", "true");
		}else if("false".equals(request.getParameter("embed"))){
			request.getSession().removeAttribute("wiki_embed");
		}
		
		if("true".equals(request.getSession().getAttribute("wiki_embed"))){
			this.embed = true;
		}else{
			this.embed = false;
		}
		
		if(null != pageInfo){
			if(embed && isViewArticle()){
				request.getSession().setAttribute(EnvironmentEx.CONST_RETURN_TO,ServletUtilEx.buildTopicUrlNoEdit(request,pageInfo));	
			}		
		}
	}
}
